-- Numbers --

	-- Returns value in range [.min, .max)
	-- Split into 2 intervals to reduce recursion levels
between .min .max (.out) :-
	.min < .max,
	let .min1 (.min + 1),
	let .mid ((.min1 + .max) / 2) !
	.out = .min;
	between .min1 .mid .out;
	between .mid .max .out #

maximum .a .b (.c) :-
	if (.a > .b) then (.c = .a) else (.c = .b) #

minimum .a .b (.c) :-
	if (.a < .b) then (.c = .a) else (.c = .b) #

	-- The way to convert between string and number
string.number .string .number :- select
	(bound .number => concat .number .string)
	(bound .string => let .number .string) ! #


-- Strings --

char.at .s .i .c :-
	if (free .i) then (length .s .len, between 0 .len .i),
	let .i1 (.i + 1), substr .s .i .i1 .c #

fill . 0 "" #
fill .e 1 .e #
fill .e (.n) (.ret) :-
	.n >= 2,
	let .div2 (.n shr 1), fill .e .div2 .s1,
	let .mod2 (.n and 1), fill .e .mod2 .s2,
	concat .s1 .s1 .s2 .ret #

delimit .str .delim .left .right :-
	nth .str .pos .delim,
	substr .str 0 .pos .left,
	let .pos1 (.pos + 1),
	substr .str .pos1 0 .right #

split "" . $ :- ! #
split .str .delim (.head, .tail) :-
	delimit .str .delim .head .remains !
	split .remains .delim .tail #
split .str . (.str,) #

split .string .list :- split .string " " .list #

lower .s .lower :-
	is.string .s,
	stream.createBuffer LOWER.STREAM,
	stream.put LOWER.STREAM .s,
	lowerStream LOWER.STREAM .lower,
	stream.close LOWER.STREAM #

lowerStream .buf .lower :-
	stream.get .buf .c !
	lowerChar .c .c1,
	lowerStream .buf .remains,
	concat .c1 .remains .lower #
lowerStream . "" #

lowerChar .c .c1 :-
	if (compare .c "A"; compare "Z" .c) then (
		.c1 = .c
	) else (
		ascii .c .a, let .a1 (.a + 32), ascii .c1 .a1
	) #


-- Data Manipulation --

tuple.concat .l1 .l2 (.ret) :-
	length .l1 .len1,
	length .l2 .len2,
	let .len (.len1 + .len2),
	length .ret .len,
	mnth .ret 0 .len1 .l1,
	mnth .ret .len1 0 .l2 #

	-- Duplicates a structure. Free variable are re-created
duplicate .o .o1 :- transform.leaves .o:.o1 .v:. (free .v) #

traverse .elem .elem #
traverse .object .elem :-
	child .object .child, traverse .child .elem #

traverse.leaves .elem .elem :-
	elementary .elem ! #
traverse.leaves .object .elem :-
	child .object .child, traverse.leaves .child .elem #

child .tuple .child :-
	is.tuple .tuple, nth .tuple . .child #
child .tree .child :-
	infix .tree .left . .right, (.child = .left; .child = .right) #

transform .obj:.obj .:. . :- -- Speed up processing leaves
	elementary .obj ! #
transform .obj0:.obj1 .arg0:.arg1 .cb :-
	gdup .obj0 .obj1,
	forall (gnth .obj0 .n .i0) (
		local .arg0 .arg1 (
			.arg0 = .i0,
			trail (.cb, gnth .obj1 .n .arg1)
		)
	) ! #

transform.recursive .obj0:.obj1 .arg0:.arg1 .cb :-
	bound .obj0,
	transform .obj0:.obj .i0:.i1 (
		transform.recursive .i0:.i1 .arg0:.arg1 .cb
	);
	.obj = .obj0
	!
	local .arg0 .arg1 (.arg0 = .obj, trail .cb, .arg1 = .obj1);
	.obj = .obj1
	! #

transform.leaves .obj0:.obj1 .arg0:.arg1 .cb :-
	elementary .obj0 !
	local .arg0 .arg1 (.arg0 = .obj0, trail .cb, .arg1 = .obj1);
	.obj0 = .obj1
	! #
transform.leaves .obj0:.obj1 .arg0:.arg1 .cb :-
	gdup .obj0 .obj1,
	forall (gnth .obj0 .n .i0) (
		transform.leaves .i0:.i1 .arg0:.arg1 .cb,
		trail (gnth .obj1 .n .i1)
	) ! #

elementary .elem :-
	is.atom .elem; is.string .elem; is.number .elem; free .elem #

	-- Duplicates the structure but not the children
gdup .tree .tree1 :-
	infix .tree . .op ., infix .tree1 . .op . #
gdup .tuple .tuple1 :-
	is.tuple .tuple, length .tuple .len, length .tuple1 .len #
gdup .elem .elem :-
	elementary .elem #

gnth .tree .i .elem :- -- Generic version of nth
	infix .tree .left . .right, (
		.i = -1, .elem = .left;
		.i = 1, .elem = .right
	) #
gnth .tuple .i .elem :-
	is.tuple .tuple, nth .tuple .i .elem #
